#include <initializer_list>

//Case 1: The type specifier is a pointer or reference, but not a universal reference.
void test_case1_PtrOrRef()
{
    const auto& rx = 128;   //rx is const int&
    const auto& rx1 = rx;   //rx1 is still const int&, reference is ignored. 
    auto& rx2 = rx;         //rx2 is const int&, const will be reserved. 
}

//Case 2: The type specifier is a universal reference.
void test_case2_UniversalRef()
{
    auto x = 128;
    const auto cx = x;

    auto&& uref1 = x;       //lvalue, uref1 is int&
    auto&& uref2 = cx;      //lvalue, uref2 is const int&
    auto&& uref3 = 128;     //rvalue, uref3 is int&&

    const auto&& uref4 = 128;   //const int&& 
    // some notes about const rvalue ref, 
    // rvalue is designed to support move, which means change of the object, const make it impossible, 
    // so const rvalue ref is not useful so much. 
    // Language still has it designed, mostly it is used to disable some features. 
    // such as, make const rvalue ref not to be able to as argument for template, or function etc. 
}

//Case 3: The type specifier is neither a pointer nor a reference.
void test_case3_NotRefPtrOrURef()
{
    auto x = 128;       // x is int. 
    const auto x1 = x;  // x1 is const int
    auto x2 = x1;       // x2 is int, const is ignored. 
    
    auto& rx = x;
    auto x3 = rx;       // x3 in int, ref is ignored. 
}

//Case 4, array and function
void case4_someFunc(double, int) {}
void test_case4_ArrayOrFunction()
{
    const char name[] = "Array";
    auto arr1 = name;       //arr1 is const char*
    auto& arr2 = name;      //arr2 is char(&)[5]

    auto func1 = case4_someFunc;    //func1 is void (*)(double,int)
    auto& func2 = case4_someFunc;   //func2 is void (&)(double, int)
}

//Case 5, {...} initializer inside braces. 
void test_case5_braces()
{
    auto a = {1};   //Visual Studio 2010 deduces it to int, does not match the std.
					//Visual Studio 2013 is following the c++11 standard. 
    //auto a = {1,2}; //Does not support in Visual studio 2010.
}


// Test entry
int Test_I02_AutoTypeDeduction(int, char**)
{
    test_case1_PtrOrRef();
    test_case2_UniversalRef();
    test_case3_NotRefPtrOrURef();
    test_case4_ArrayOrFunction();
    test_case5_braces();

    return 0;
}

/*
Things to Remember
- auto type deduction is normally identical to template type deduction.
- The sole exception is that in variable declarations using auto and braced initializers, auto deduces std::initializer_lists.
- Template type deduction fails for braced initializers.
*/
